package com.ypj.rpc.transport;

import com.ypj.rpc.annotation.Service;
import com.ypj.rpc.annotation.ServiceScan;
import com.ypj.rpc.enumeration.RpcError;
import com.ypj.rpc.exception.RpcException;
import com.ypj.rpc.provider.ServiceProvider;
import com.ypj.rpc.registry.ServiceRegistry;
import com.ypj.rpc.utils.ReflectUtil;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.Set;

@Slf4j
public abstract class AbstractRpcServer implements RpcServer {
    protected String host;
    protected int port;

    protected ServiceRegistry serviceRegistry;
    protected ServiceProvider serviceProvider;

    public void scanServices(){
        String mainClassName= ReflectUtil.getStackTrace();
        Class<?> startClass;
        try {
            startClass=Class.forName(mainClassName);
            if (!startClass.isAnnotationPresent(ServiceScan.class)){
                log.error("启动类缺少@ServiceScan注解");
                throw new RpcException(RpcError.SERVICE_SCAN_PACKAGE_FAILURE.getMessage());
            }
        } catch (ClassNotFoundException e) {
            log.error("出现未知错误");
            throw new RpcException(RpcError.UNKNOWN_ERROR.getMessage());
        }
        //注解所在的启动类所在的包位置为默认扫描位置
        String basePackage=startClass.getAnnotation(ServiceScan.class).value();
        if ("".equals(basePackage)){
            basePackage=mainClassName.substring(0,mainClassName.lastIndexOf('.'));
        }
        Set<Class<?>> classSet=ReflectUtil.getClasses(basePackage);
        for (Class<?> clazz:classSet){
            if (clazz.isAnnotationPresent(Service.class)){
                //获取@Service注解标识的所有服务名称默认""
                String serviceName=clazz.getAnnotation(Service.class).name();
                Object obj;
                try {
                    obj=clazz.newInstance();
                } catch (InstantiationException | IllegalAccessException e) {
                    log.error("创建"+clazz+"时发生错误");
                    continue;
                }
                if ("".equals(serviceName)){
                    //默认类下等到"",因此需要循环得到serviceName
                    Class<?>[] interfaces=clazz.getInterfaces();
                    for (Class<?> oneInterface:interfaces){
                        publishService(obj,oneInterface.getCanonicalName());
                    }
                }else{
                    publishService(obj,serviceName);
                }
            }
        }

    }

    @Override
    public <T> void publishService(T service,String serviceName) {
        serviceProvider.addServiceProvider(service);
        serviceRegistry.register(serviceName, new InetSocketAddress(host, port));
    }
}
